﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Web.UI;
using System.ComponentModel;
using TA.Turbo.Design;
using System.Drawing.Design;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// Base class for all validators.
	/// </summary>
	public abstract class BaseValidator : BaseComplexControl
	{
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		public BaseValidator()
		{
			Tag = HtmlTextWriterTag.Span;
			Style[HtmlTextWriterStyle.Color] = "red";
		}
		#endregion
		#region PROPERTIES
		#region DEF
		/// <summary>
		/// Props.
		/// </summary>
		protected static new Properties _clientProperties = Define(BaseComplexControl._clientProperties,
			new BasePropertyDefinition[] 
			{
				new PropertyDefinition<string>("Group","G", null),
				new PropertyDefinition<string>("InlineMessage", "IM", "*") { IsHTML = true },
				new PropertyDefinition<string>("SummaryMessage", "SM","This field is required."),
				new PropertyDefinition<bool>("IsValid", "IV", true),
				new PropertyDefinition<bool>("ValidateEmpty", "VE", false),
				new EnumPropertyDefinition<ValidatorDisplay>("Display", "VD", ValidatorDisplay.Static),
				new ControlIdPropertyDefinition("ValidatedControlId", "VC", null),
			});
		/// <summary>
		/// Props.
		/// </summary>
		public override Properties ClientProperties
		{
			get
			{
				return _clientProperties;
			}
		}
		#endregion
		/// <summary>
		/// The group which this validator belongs to.
		/// </summary>
		[DefaultValue("")]
		[Editor(typeof(ValidationGroupEditor), typeof(UITypeEditor))]
		public string Group
		{
			get
			{
				return GetProperty<string>("Group");
			}
			set
			{
				ViewState["Group"] = value;
			}
		}
		/// <summary>
		/// Message displayed inside the validator.
		/// </summary>
		public string InlineMessage
		{
			get
			{
				return GetProperty<string>("InlineMessage");
			}
			set
			{
				ViewState["InlineMessage"] = value;
			}
		}
		/// <summary>
		/// Message displayed as part of the summary.
		/// </summary>
		public string SummaryMessage
		{
			get
			{
				return GetProperty<string>("SummaryMessage");
			}
			set { ViewState["SummaryMessage"] = value; }
		}
		/// <summary>
		/// Display mode.
		/// </summary>
		[DefaultValue(ValidatorDisplay.Static)]
		public ValidatorDisplay Display
		{
			get
			{
				if (ViewState["Display"] != null)
					return GetProperty<ValidatorDisplay>("Display");
				return ValidatorDisplay.Static;
			}
			set
			{
				ViewState["Display"] = value;
			}
		}
		/// <summary>
		/// The ID of the control to be validated.
		/// </summary>
		[IDReferenceProperty]
		[TypeConverter(typeof(ControlIdConverter<ValueControlIdLister>))]
		[DefaultValue("")]
		[MergableProperty(false)]
		public string ValidatedControlId
		{
			get
			{
				return GetProperty<string>("ValidatedControlId");
			}
			set
			{
				ViewState["ValidatedControlId"] = value;
				ViewState.SetItemDirty("ValidatedControlId", true);
			}
		}
		/// <summary>
		/// Gets the control to be validated.
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public BaseValueControl ValidatedControl
		{
			get
			{
				BaseValueControl c = this.FindControlGlobal(ValidatedControlId) as BaseValueControl;
				return c;
			}
		}
		/// <summary>
		/// If the control is an <see cref="IValueControlContainer"/>, gets a reference to it.
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public IValueControlContainer ValidatedValueControlContainer
		{
			get
			{
				IValueControlContainer c = this.FindControlGlobal(ValidatedControlId) as IValueControlContainer;
				return c;
			}
		}
		/// <summary>
		/// Gets the value of the validated control.
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public object ValidatedValue
		{
			get
			{
				return ValidatedControl == null ? null : ValidatedControl.GenericValue;
			}
		}
		/// <summary>
		/// True if valid, false if not.
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool IsValid
		{
			get
			{
				return GetProperty<bool>("IsValid");
			}
		}
		/// <summary>
		/// True if this validator should validate on the server side.
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool IsServerValidated
		{
			get
			{
				return !this.IsTemplated;
			}
		}
		/// <summary>
		/// If false (default), will not validate control if value not set.
		/// </summary>
		[DefaultValue(false)]
		public virtual bool ValidateEmpty
		{
			get
			{
				return this.GetProperty<bool>("ValidateEmpty");
			}
			set
			{
				ViewState["ValidateEmpty"] = value;
			}
		}
		#endregion
		#region METHODS
		/// <summary>
		/// Validates the associated control.
		/// </summary>
		public void Validate()
		{
			if (this.ValidateEmpty ||
				(this.ValidatedControl.GenericValue != null && this.ValidatedControl.GenericValue.ToString() != ""))
				this.DoValidate();
		}
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		#endregion
		#region PROPS

		#endregion
		#region METHODS
		#region VALIDATION
		/// <summary>
		/// When implemented, performs the validation.
		/// </summary>
		protected abstract void DoValidate();
		/// <summary>
		/// Sets the valid status of this control.
		/// </summary>
		/// <param name="isValid"></param>
		protected void SetValidStatus(bool isValid)
		{
			ViewState["IsValid"] = isValid;
		}
		#endregion
		#region INIT
		/// <summary>
		/// Initialization.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);


			if (!this.get_IsDesignMode())
			{
				this.ResolveValidatedControl();
				if (this.ValidatedControl != null)
					this.TPage.Validators.Add(this);
			}
		}
		/// <summary>
		/// Registers BaseValidator.js.
		/// </summary>
		protected internal override void RegisterIncludes(IncludeCollection includes)
		{
			base.RegisterIncludes(includes);

			includes.Add(Script.DataType);
			includes.Add(Script.ResponseValidator);
			includes.Add(new ScriptResourceInclude("TA.Turbo.Res.JS.Validators.Turbo_Validate.js", typeof(BaseValidator)));
			includes.Add(new ScriptResourceInclude("TA.Turbo.Res.JS.Validators.BaseValidator.js", typeof(BaseValidator)));
		}
		#endregion
		#region RENDER
		/// <summary>
		/// Adds attributes for <see cref="Display"/>.
		/// </summary>
		/// <param name="writer"></param>
		protected override void AddAttributesToRender(HtmlTextWriter writer)
		{
			switch (Display)
			{
				case ValidatorDisplay.Dynamic:
					Style[HtmlTextWriterStyle.Display] = IsValid ? "none" : "";
					break;
				case ValidatorDisplay.Static:
					Style[HtmlTextWriterStyle.Visibility] = IsValid ? "hidden" : "";
					break;
				case ValidatorDisplay.None:
					Style[HtmlTextWriterStyle.Display] = "none";
					break;
			}

			base.AddAttributesToRender(writer);
		}
		/// <summary>
		/// Writes the inline message.
		/// </summary>
		/// <param name="writer"></param>
		protected override void RenderContents(HtmlTextWriter writer)
		{
			writer.Write(InlineMessage);

			if (this.get_IsDesignMode())
			{
				if (string.IsNullOrEmpty(this.InlineMessage))
					writer.Write(this.GetType().Name);
			}
		}
		/// <summary>
		/// Resolves the validated control.
		/// </summary>
		protected virtual void ResolveValidatedControl()
		{
			if (ValidatedControl == null)
			{
				if (ValidatedValueControlContainer != null)
				{
					if (ValidatedValueControlContainer.Validatable != null)
					{
						ValidatedControlId = ValidatedValueControlContainer.Validatable.UniqueID;
						ResolveValidatedControl();
						return;
					}
				}
				else
					this.Parent.Controls.Remove(this);

			}
		}
		#endregion
		#endregion
		#endregion
	}
}
